
#include <string.h>
#include "httpmsg.h"

namespace datashuttle
{

HttpMessage::HttpMessage()
	:mMethod(HTTP_MTD_GET),
	mProtocol(0),
	mBodySize(0)
{
}

HttpMessage::~HttpMessage()
{
}

HttpMethod HttpMessage::getMethod() const
{
	return mMethod;
}

const std::string& HttpMessage::getUri() const
{
	return mUri;
}

std::string HttpMessage::getHeader( const std::string& key ) const
{
	HEADERS::const_iterator it = mHeaders.find( key );
	if( it == mHeaders.end() )
		return 	std::string("");
	return it->second;
}

int HttpMessage::getProtocol() const
{
	return mProtocol;
}
bool HttpMessage::isBodyChunked() const
{
	return mBodySize == size_t(-1);
}

size_t HttpMessage::getBodySize() const
{
	if( isBodyChunked())
		return 0;
	return mBodySize;
}

void HttpMessage::setUri( const std::string& uri )
{
	mUri = uri;
}

void HttpMessage::setProtocol( int p )
{
	mProtocol = p;
}

void HttpMessage::setMethod( HttpMessage mtd)
{
	mMethod = mtd;
}

void HttpMessage::setHeader( const std::string& key, const std::string& value )
{
	mHeaders[key] = value;
}

void HttpMessage::removeHeader( const std::string& key )
{
	mHeaders.erase( key );
}


///////////////////////////////////////////////////////////////////////////

HttpMsgParser::LineParser::LineParser( const char*& data, size_t& size, std::string& reserved )
	:mpData(data),mSize(size),mRefReserved(reserved)
{
	assert(size > 0 );
}
HttpMsgParser::LineParser::~LineParser()
{
}

bool HttpMsgParser::LineParser::getNextline( const char*& p, size_t& size )
{
	p = 0;
	size = 0;
	if( mSize <= 0 || mpData == 0 )	
		return false;
	const char* str = strstr( mpData , "\n");
	if( !str )
	{
		//store the data into reserved string
		mRefReserved.assign(mpData,mSize);
		mpData= 0;
		mSize = 0;
		return false;
	}
	size  = str - mpData;
	mSize -= size + 1 ;
	if( size > 0 )
	{
		if( p[-1] == '\r')
			-- size;
	}

	mpData = p + 1;

	if( !mRefReserved.empty() )
	{
		mRefReserved.clear();
		mReserved = mRefReserved;
		mReserved.append( str, size );
		size = mReserved.size();
		p = &mReserved[0];
	}
	else
	{
		p = str;
	}
	return true;
}

HttpMsgParser::LineSplitter::LineSplitter(const char* data, size_t size )
	:mpData(data), mSize(size)
{
	mDilemeter = ' ';
	mDileSize = 1;
	mTrimStr = ' \t';
	mTrimSize = 2;
}

HttpMsgParser::LineSplitter::~LineSplitter()
{
}

void HttpMsgParser::LineSplitter::setDilemeter( const char* dilemeter =' ', size dileSize = 1,
												const char* trimChar =' \t', size_t trimSize = 2 )
{
	mDilemeter	= dilemeter;
	mDileSize	= dileSize;

	mTrimStr	= trimChar;
	mTrimSize	= trimSize;
}

size_t HttpMsgParser::LineSplitter::findsubstr( const char* p, size_t sz )
{
	if(!p || sz <= 0 )
		return 0;//意味着如果没有substr来供查找的话，那么就返回字符串的地一个字符的位置
	
	if( mSize < sz )
		return (size_t)-1;

	bool bFound = false;
	for( size_t i = 0 ; i < mSize ; i ++ )
	{
		if(mpData[i] != p[0] )
			continue;

		bFound = true;
		const char* q = &mpData[i];
		for( size_t j = 1 ; j < sz ; j ++ )
		{
			if( q[j] != p[j] )
			{
				bFound = false;
				break;
			}
		}
		if(bFound )
		{
			return i;
		}
	}
	return (size_t)-1;
}

size_t HttpMsgParser::LineSplitter::findlastnotof( const char* p , size_t sz )
{
	size_t lastpos = mSize > 0 : mSize - 1 : 0;
	if( !p || sz <= 0 )
		return lastpos;
	if( mSize < sz )
		return lastpos;

	bool bFound = false;
	for( size_t i = lastpos - sz ; i >= 0 ; i --)
	{
		bFound = false;
		const char& c = mpData[i];
		for( size_t j = 0 ; j < mTrimSize; j ++ )
		{
			if( c == mTrimStr[j] )
			{
				bFound = true;
				break;
			}
		}
		if( !bFound )
		{
			mpData += i;
			mSize -= i;
			return i;
		}
	}
	mpData += mSize;
	mSize = 0;
	return (size_t)-1;
}

size_t HttpMsgParser::LineSplitter::findfirstnotof( const char* p , size_t sz )
{
	if( !p || sz <= 0 )
		return 0;
	if( mSize < sz )
		return 0;

	bool bFound = false;
	for( size_t i = 0 ; i < mSize; i ++)
	{
		bFound = false;
		const char& c = mpData[i];
		for( size_t j = 0 ; j < mTrimSize ; j++ )
		{
			if( c == mTrimStr[j] )
			{
				bFound = true;
				break;
			}
		}

		if(!bFound )
		{
			mpData += i;
			mSize -= i;
			return i;
		}
	}
	mpData += mSize;
	mSize = 0;
	return (size_t)-1;
}

#define POSOK(x) ( x!= (size_t)-1 ) 
const char* HttpMsgParser::LineSplitter::nextpart( size_t& size )
{
	const char* ret = 0;
	size  = 0;

	if( !mDilemeter || mDileSize <= 0 )
	{
		size = mSize;
		return mpData;
	}
	if( !mpData || mSize <= 0 )
		return 0;

	size_t startPos = 0;
	//首先找出第一个不是dilemeter的字符
	if( mTrimStr && mTrimSize > 0 )
	{
		startPos = findnotof(mTrimStr, mTrimSize);
		if( !POSOK(startPos) )
		{//没有找到
			return 0;
		}
	}

	ret = mpData;//记录数据开始的位置

	size_t endPos = findsubstr( mDilemeter, mDileSize ) ;

	if( !POSOK(endPos) )
	{
		size = mSize;
		return ret;
	}

	const char* tmp = mpData;
	size = tmp - ret;
	
	return ret;
}

///////////////////////////////////////////////////////////////////////////
HttpMsgParser::HttpMsgParser()
	:mParseState(STATE_FIRSTLINE),
	mHttpMsg(0)
{
	mReserved.reserve( 1024 );//allocate at least 1k bytes for temporary hold the un-parsed data
}

HttpMsgParser::~HttpMsgParser()
{
	if( mHttpMsg )
	{
		delete mHttpMsg;
	}
}

struct HttpMethodInfo
{
	const char*	p;
	size_t		size;
	HttpMethod	mtd;
};

static HttpMethodInfo _httpMethod[]=
{
	{"GET",		3,	HTTP_MTD_GET	},
	{"POST",	4,	HTTP_MTD_POST	},
	{"PUT",		3,	HTTP_MTD_PUT	},
	{"DELETE",	6,	HTTP_MTD_DELETE	},
};

HttpMethod	HttpMsgParser::parseHttpMethod( const char* p, size_t sz )
{
	static size_t methodcount = sizeof(_httpMethod ) /sizeof(HttpMethodInfo);
	for( size_t i = 0 ; i < methodcount ; i ++ )
	{
		const HttpMethodInfo& info = _httpMethod[i];
		if( info.size == sz && strncmp(p,info.p,sz) == 0 )
		{
			return info.mtd;
		}
	}
	retur HTTP_MTD_UNKNOWN;
}

HttpMessage* HttpMsgParser::parse( const char* data, size_t size )
{
	if(!data || size <= 0 )
		return 0;
	
	if(!mHttpMsg)
	{
		mHttpMsg = new HttpMessage();
		mParseState = STATE_FIRSTLINE;
		mConsumedBodySize = 0 ;
	}

	LineParser lp(data, size, mReserved );

	const char *p = NULL;
	size_t lineLength = 0;
	
	while( size >  0 )
	{
		switch( mParseState )
		{
		case STATE_FIRSTLINE:
			{
				//如果无法正确解析出一行数据,那么证明数据不够,需要等到下一次的数据
				if(!lp.getNextline(p,lineLength ) )
					return 0;
				if( lineLength <= 0 )
					continue;//得到了一个正常的first line，但是很不幸，没有得到有效数据
				LineSplitter ls(p, lineLength);
				size_t tmpSize = 0 ;
				
				const char* pVerb = ls.nextpart( tmpSize );
				if( !pVerb )
				{//invalid start line
					break;
				}
				HttpMethod mtd = parseHttpMethod( pVerb, tmpSize );
				if( mtd == HTTP_MTD_UNKNOWN )
				{//what to do if verb is not correct
					//discard the whole message data?
				}

			}
			break;
		case STATE_HEADER:
			{
				lineLength = 0;
				do
				{
					if(!lp.getNextline(p,lineLength))
						return 0;
					if( lineLength <= 0 )
					{//end of headers
						mParseState = STATE_BODY;
						break;
					}
					if(! parseHeader(p,lineLength))
					{
						if(!onBadFormat("bad header format"))
							return 0;
					}
				}while( lineLength >0 );
			}
			break;
		case STATE_BODY:
			{
				size_t sz = mHttpMsg->getBodySize();
				if( sz == (size_t)-1 )
				{//chunked data

				}
				else
				{

				}
			}
			break;
		case STATE_DONE:
			{
			}
			break;
		default:
			break;
		}
	}
	return 0;
}

bool HttpMsgParser::parseStartLine( const char* p, size_t size )
{
	if(!p || size <= 0 )
		return false;
	
	size_t tmpSize = 0 ;

	LineSplitter ls(p, size);

	const char* pVerb = ls.nextpart( tmpSize );
	if( !pVerb || tmpSize <= 0 )
		return false;
	
	HttpMethod mtd = parseHttpMethod( pVerb, tmpSize );
	if(mtd == HTTP_MTD_NULL)
		return false;
	mHttpMsg->setMethod(mtd);

	const char* pUri = ls.nextpart( tmpSize );
	if(!pUri || tmpSize <=0 )
		return false;
	std::string uri(pUri, tmpSize);
	mHttpMsg->setUri(uri);

	const char* pProtocol = ls.nextpart( tmpSize )
	if(!pProtocol || tmpSize <=0 )
		return false;
	std::string protocol(pProtocol, tmpSize);
	sscanf(protocol.c_str(),"HTTP/1.%u",&tmpSize);
	if( tmpSize < 0 || tmpSize > 1 )
		return false;
	mHttpMsg->setProtocol(tmpSize + 1);
	return true;
}

}//namespace datashuttle


